package com.taotao.controller;

import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;

public class RsaUtils {

	    /**
	     * RSA最大加密明文大小
	     */
	    private static final int MAX_ENCRYPT_BLOCK = 117;

	    /**
	     * RSA最大解密密文大小
	     */
	    private static final int MAX_DECRYPT_BLOCK = 128;

	    /**
	     * 获取密钥对
	     * 
	     * @return 密钥对
	     */
	    public static KeyPair getKeyPair() throws Exception {
	        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
	        generator.initialize(1024);
	        return generator.generateKeyPair();
	    }

	    /**
	     * 获取私钥
	     * 
	     * @param privateKey 私钥字符串
	     * @return
	     */
	    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
	        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
	        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
	        return keyFactory.generatePrivate(keySpec);
	    }

	    /**
	     * 获取公钥
	     * 
	     * @param publicKey 公钥字符串
	     * @return
	     */
	    public static PublicKey getPublicKey(String publicKey) throws Exception {
	        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
	        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
	        return keyFactory.generatePublic(keySpec);
	    }
	    
	    /**
	     * RSA加密
	     * 
	     * @param data 待加密数据
	     * @param publicKey 公钥
	     * @return
	     */
	    public static String encrypt(String data, PublicKey publicKey) throws Exception {
	        Cipher cipher = Cipher.getInstance("RSA");
	        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
	        int inputLen = data.getBytes().length;
	        ByteArrayOutputStream out = new ByteArrayOutputStream();
	        int offset = 0;
	        byte[] cache;
	        int i = 0;
	        // 对数据分段加密
	        while (inputLen - offset > 0) {
	            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
	                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
	            } else {
	                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
	            }
	            out.write(cache, 0, cache.length);
	            i++;
	            offset = i * MAX_ENCRYPT_BLOCK;
	        }
	        byte[] encryptedData = out.toByteArray();
	        out.close();
	        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
	        // 加密后的字符串
	        return new String(Base64.encodeBase64String(encryptedData));
	    }

	    /**
	     * RSA解密
	     * 
	     * @param data 待解密数据
	     * @param privateKey 私钥
	     * @return
	     */
	    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
	        Cipher cipher = Cipher.getInstance("RSA");
	        cipher.init(Cipher.DECRYPT_MODE, privateKey);
	        byte[] dataBytes = Base64.decodeBase64(data);
	        int inputLen = dataBytes.length;
	        ByteArrayOutputStream out = new ByteArrayOutputStream();
	        int offset = 0;
	        byte[] cache;
	        int i = 0;
	        // 对数据分段解密
	        while (inputLen - offset > 0) {
	            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
	                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
	            } else {
	                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
	            }
	            out.write(cache, 0, cache.length);
	            i++;
	            offset = i * MAX_DECRYPT_BLOCK;
	        }
	        byte[] decryptedData = out.toByteArray();
	        out.close();
	        // 解密后的内容 
	        return new String(decryptedData, "UTF-8");
	    }

	    /**
	     * 签名
	     * 
	     * @param data 待签名数据
	     * @param privateKey 私钥
	     * @return 签名
	     */
	    public static String sign(String data, PrivateKey privateKey) throws Exception {
	        byte[] keyBytes = privateKey.getEncoded();
	        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	        PrivateKey key = keyFactory.generatePrivate(keySpec);
	        Signature signature = Signature.getInstance("MD5withRSA");
	        signature.initSign(key);
	        signature.update(data.getBytes());
	        return new String(Base64.encodeBase64(signature.sign()));
	    }

	    /**
	     * 验签
	     * 
	     * @param srcData 原始字符串
	     * @param publicKey 公钥
	     * @param sign 签名
	     * @return 是否验签通过
	     */
	    public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
	        byte[] keyBytes = publicKey.getEncoded();
	        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	        PublicKey key = keyFactory.generatePublic(keySpec);
	        Signature signature = Signature.getInstance("MD5withRSA");
	        signature.initVerify(key);
	        signature.update(srcData.getBytes());
	        return signature.verify(Base64.decodeBase64(sign.getBytes()));
	    }

	    public static void main(String[] args) {
	        try {
	            // 生成密钥对
	            KeyPair keyPair = getKeyPair();
	            String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
	            String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
	            System.out.println("私钥:" + privateKey);
	            System.out.println("公钥:" + publicKey);
	            // RSA加密
	            String data = "待加密的文字内容";
	            String encryptData = encrypt(data, getPublicKey(publicKey));
	            System.out.println("加密后内容:" + encryptData);
	            // RSA解密
	            String decryptData = decrypt(encryptData, getPrivateKey(privateKey));
	            System.out.println("解密后内容:" + decryptData);
	            
	            // RSA签名
	            String sign = sign(data, getPrivateKey(privateKey));
	            // RSA验签
	            boolean result = verify(data, getPublicKey(publicKey), sign);
	            System.out.println("验签结果:" + result);
	            System.out.println("--------------------");
	            /*我方会提供接入方对应的商家公私钥一对，商家发送请求时，使用商家私钥进 行签名，
	            并对消息报文内容使用商家公钥作为key进行3DES对称加密，然后请 求慧运网关，传输报文；
	            慧运网关接收请求报文后，会使用商家公钥进行验 签，再进行报文解密。
	            公私钥串示例如下：
	            {
				"ts": 1556443469911,
				"sign": "e80b5017098950fc58aad83c8c14978e",
				"data": {
				"date": "2019-07-23",
				"userType": "A",
				"receiveDataCount": 580,
				"callTimes": 576,
				"answerCount": 570,
				"successCount": 553,
				"perSuccess": 61 } }
	            */
	            
	            String dataStr="{userType:A,perSuccess:61 }";
	            System.out.println("原内容："+dataStr);
	            String dataStrDes=Des3Util.byte2Hex(Des3Util.encryptMode(dataStr.getBytes()));
	            System.out.println("3de加密x后的data："+dataStrDes);
	            String sign2 = sign(dataStrDes, getPrivateKey(privateKey));
	            System.out.println("签名："+sign2);
	            
	            boolean result2= verify(dataStrDes, getPublicKey(publicKey), sign2);
	            System.out.println("验签结果:" + result2);
	         // 解密
	            byte[] myMsgArr = Des3Util.decryptMode(Des3Util.hex2byte(dataStrDes));
	            System.out.println("【解密后】：" + new String(myMsgArr));
	            
	            
	        } catch (Exception e) {
	            e.printStackTrace();
	            System.out.print("加解密异常");
	        }
	    }
	}